<template>
  <div id="vregularExp">
    正则表达式
    <hr />
    <h1>vue</h1>
    <h1>java</h1>
    <h1>js</h1>
    <hr />
    <p>邮箱验证中原子组的使用</p>
    <input type="text" v-model="mail" />
    <el-button @click="testRegEx23">校验</el-button>
    <hr />
    <p>批量使用正则做输入内容校验</p>
    <div>
      <input
        style="margintop: 10px; width: 500px"
        placeholder="请输入以3为字符，字母数字开头，必须包含大写字母和数字"
        type="text"
        @keyup="testRegEx28"
        v-model="password"
      />
      <div>结果：{{ testRegEx28() }}</div>
    </div>

    <hr />
    <p>正则表达式中：$&的使用</p>
    <p id="myContent35">学好正则，开发高效！</p>

    <hr />
    <p>原子组在替换中的使用技巧</p>
    <div id="myContent36">
      <a href="https://www.dcr.com/" style="color: red">稻草人</a>
      <a href="https://hmgdcr.com/">HMGDCR</a>
      <a href="http://yahoo.com">雅虎</a>
      <h4>http://www.hdcms.com</h4>
    </div>

    <hr />
    <p>test做邮箱验证</p>
    <input type="text" v-model="email" @keyup="testRegEx40" />
    验证结果：{{ isEmail ? "正确" : "错误" }}

    <hr />
    <p>exec的使用统计“稻草人”出现的次数：</p>
    <div>出现次数：{{ num }} 次</div>
    <div id="content41">
      童话《稻草人》以稻草人的眼目，观照惨痛的世情：可怜的农妇、可怜的渔妇、可怜的自杀者、可怜的鲫鱼等等。然而对于人世间的悲剧，稻草人什么都挽救不了、改变不了。最终，在内疚感与无力感之间纠结的稻草人“倒在田地中间”，与悲剧同眠。鲁迅：“《稻草人》是给中国的童话开了一条自己创作的路的”。（出自《表·译者的话》）
      [4]
    </div>
    <p id="content42" style="margintop: 20px">AA正则CC； AA正则； 正则CC;</p>

    <hr />
    <div>
      <p>?!限制用户输入“稻草人”</p>
      <div style="margintop: 20px">
        <input type="text" v-model="search" @keyup="testRegEx45" />
        <br />
        正确：{{ enSearch ? "允许" : "不允许" }}
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      mail: "",
      password: "",
      email: "",
      isEmail: false,
      num: 0,
      search: "",
      enSearch: false,
    };
  },

  methods: {
    testRegEx0() {
      let str = "123abc456def";
      console.log([...str]); // ['1', '2', '3', 'a', 'b', 'c', '4', '5', '6', 'd', 'e', 'f']

      //   let nums =   [...str].filter(a => {
      //        let b = !Number.isNaN(parseInt(a))
      //        console.log('b==',b);
      //        if (b) {
      //            return b
      //        }
      //     } )

      // 简写为
      let nums = [...str].filter((a) => !Number.isNaN(parseInt(a)));

      console.log("nums:", nums);
      console.log("非正则表达式:", nums.join(""));

      // 正则表达式
      console.log("正则表达式：", str.match(/\d/g).join(""));
    },
    testRegEx1() {
      // 字面量创建正则表达式
      let str = "123abc456def";
      console.log("测试字符串中是否含a:", /a/.test(str)); // true

      // 字面量不能检测变量
      let u = "a";
      console.log("测试字符串中是否含a:", /u/.test(str)); // false

      // 可以使用eval
      console.log("测试字符串中是否含a:", eval(`/${u}/`).test(str)); // true
    },

    testRegEx2() {
      // 第一个参数 查找的字符串u
      // 第二个参数 匹配模式g

      let str = "123abcduf";
      let reg1 = new RegExp("u", "g");
      console.log("查字符串中u:", reg1.test(str));

      // 对象创建表达式 可以传递变量
      let variable = "u";
      let reg2 = new RegExp(variable, "g");
      console.log("查字符串中u:", reg2.test(str)); // true
    },

    testRegEx3() {
      let str = "123abc456def";
      // 只要左右两边任意表达式满足即可，注意不是满足字符，而是表达式
      let reg1 = /ab|c/;
      console.log("选择符的使用：", reg1.test(str)); // true
    },

    testRegEx4() {
      // 原子表会查找原子表中的每一个字符
      let reg1 = /[123456a]/;
      let str1 = "a";
      // ['a', index: 0, input: 'a', groups: undefined]
      console.log("原子表：", str1.match(reg1));

      // 原子组，选择符任意两边满足都可以
      let reg2 = /(1q2|34)/;
      let str2 = "123456";
      // ['34', '34', index: 2, input: '123456', groups: undefined]
      console.log("原子组：", str2.match(reg2));
    },
    testRegEx5() {
      let price = 24.23;
      // +表示重复匹配
      // .除换行外任意字符（优先级最高）；.任意字符
      console.log("转义：", /\d+\.\d+/.test(price)); // true

      // 在字符串里面 "\d" == "d"
      console.log("d == d", "d" == "d"); //打印： d == d true
      let reg2 = new RegExp("d+.d+");
      console.log("对象式1：", reg2.test(price)); // false

      // 正确写法
      console.log("d+.d+"); // d+.d+
      console.log("\\d+\\.\\d+"); // \d+\.\d+

      let reg3 = new RegExp("\\d+\\.\\d+");
      console.log("对象式2：", reg3.test(price)); // true
    },
    testRegEx6() {
      let str = "abcd123efg";
      console.log("字符串中含所有数字：", /\d/.test(str)); // true
      console.log("字符串中以数字开头", /^\d/.test(str)); // false
      console.log("字符串中以数字结尾", /\d$/.test(str)); // false
    },
    testRegEx7() {
      let str1 = `
        张三：010-77777777,
        李四：321-8888888
        `;
      console.log(str1.match(/\d{3}-\d{7,8}/g)); // ['010-77777777', '321-8888888']

      let str2 = "abc123";
      // \d表示数字; \D除了数字
      console.log(str2.match(/\D/)); // ['a', index: 0, input: 'abc123', groups: undefined]
      console.log(str2.match(/\D+/)); // ['abc', index: 0, input: 'abc123', groups: undefined]

      // 运用原子表过滤
      console.log(str1.match(/[-\d：,]+/g)); // ['：010-77777777,', '：321-8888888']
      console.log(str1.match(/[^-\d：,]+/g)); // ['\n        张三', '\n        李四', '\n        ']
      console.log(str1.match(/[^-\d：,\s]+/g)); // 去掉空白 ['张三', '李四']
    },
    testRegEx8() {
      let str = "abc123-";
      console.log(str.match(/\d+/)); // ['123', index: 3, input: 'abc123-', groups: undefined]

      // \w 表示字母、数字、下划线
      console.log(str.match(/\w+/)); // ['abc123', index: 0, input: 'abc123-', groups: undefined]

      // \W 表示除了字母、数字、下划线
      console.log(str.match(/\W+/)); // ['-', index: 6, input: 'abc123-', groups: undefined]
    },
    testRegEx9() {
      /**
       * \d 表示数字
       * \w 表示数字、字母、下划线
       * .  表示除了换行符外的任意字符
       */

      let str1 = "abcd";
      // 匹配出换行符外的任意字符
      console.log(str1.match(/.+/)); // ['abcd', index: 0, input: 'abcd', groups: undefined]

      let str2 = `
        www.abc.com
        www.bcd.com
        `;
      console.log(str2.match(/.+/)[0]); // www.abc.com

      // \s 视字符串为单行匹配
      console.log(str2.match(/.+/s)[0]); // www.abc.com
      // www.bcd.com
    },
    testRegEx12() {
      let str1 = `
        #1 js,300元 #
        #2 php,200元 #
        #4 java,400元 # 小张
        #5 node.js,500元 #
        `;

      // 要求变成 [name:'xxx',price: 'xx元']的形式

      /**
       *  *表示0个或多个
       *  +表示1个或多个
       *  m表示每一行单独处理
       *  .表示除了换行符外任意字符（优先级高）；表示点
       * \s 去掉空格
       *
       */
      let reg = /^\s*#\d+\s+.+\s+#$/gm;

      console.log(str1.match(reg));
      let lesson = str1.match(reg).map((v) => {
        v = v.replace(/\s*#\d+\s*/, "").replace(/\s*#/, "");
        // 利用结构
        let [name, price] = v.split(",");
        return {
          name,
          price,
        };
      });
      console.log("课程：", JSON.stringify(lesson, null, 2));
    },

    testRegEx14() {
      // 要求匹配所有的字符，并且任然保留属性
      let str = "abc";

      // 1.使用字符串的方法，
      // 不使用g的情况 缺点是没有匹配全部字符串
      console.log(str.match(/\w/)); // ['a', index: 0, input: 'abc', groups: undefined]
      // 使用g的情况 缺点是属性消失了
      console.log(str.match(/\w/g)); // ['a', 'b', 'c']

      // 2.使用正则表达式的方法，exec
      // 注意：一定使用全局模式 g
      let reg = /\w/g;
      //之所以能依次的打印字符，是因为有lastIndex属性，不断的在改变
      console.log("下标0：", reg.lastIndex); // 0
      console.log("1=", reg.exec(str)); // a
      console.log("下标1：", reg.lastIndex); // 1
      console.log("2=", reg.exec(str)); // b
      console.log("下标2：", reg.lastIndex); // 2

      // 可以采用遍历依次打印
      reg.lastIndex = 0; // 重置下标
      let res = "";
      while ((res = reg.exec(str))) {
        console.log("###=", res);
      }
    },

    testRegEx15() {
      /**
       * y模式：当匹配不符合时，下标重置为0，就算后面的字符符合也不再继续
       * g模式：当匹配不符合时，继续往后匹配，直到匹配完为止，然后重置下标为0
       */

      // y模式和g模式
      let str = "abcaefag";
      console.log("=======g模式下=========");
      // g模式下
      let reg1 = /a/g;
      console.log("g模式下标0:", reg1.lastIndex); // 0
      console.log("g模式下:", reg1.exec(str)); // ['a', index: 0, input: 'abcaefag', groups: undefined]

      console.log("g模式下标1:", reg1.lastIndex); // 1
      console.log("g模式下:", reg1.exec(str)); // ['a', index: 3, input: 'abcaefag', groups: undefined]

      console.log("g模式下标2:", reg1.lastIndex); // 4
      console.log("g模式下:", reg1.exec(str)); // ['a', index: 6, input: 'abcaefag', groups: undefined]

      console.log("g模式下标3:", reg1.lastIndex); // 7
      console.log("g模式下:", reg1.exec(str)); // null

      console.log("g模式下标4:", reg1.lastIndex); // 0
      console.log("g模式下:", reg1.exec(str)); // ['a', index: 0, input: 'abcaefag', groups: undefined]

      console.log("=======y模式下=========");
      // y模式下
      let reg2 = /a/y;
      console.log("y模式下标0:", reg2.lastIndex); // 0
      console.log("y模式下：", reg2.exec(str)); // ['a', index: 0, input: 'abcaefag', groups: undefined]

      console.log("y模式下标1:", reg2.lastIndex); // 1
      console.log("y模式下:", reg2.exec(str)); // null

      console.log("y模式下标2:", reg2.lastIndex); // 0
      console.log("y模式下", reg2.exec(str)); // ['a', index: 0, input: 'abcaefag', groups: undefined]

      console.log("y模式下标3:", reg2.lastIndex); // 1
      console.log("y模式下", reg2.exec(str)); // null

      console.log("y模式下标4:", reg2.lastIndex); // 0
      console.log("y模式下", reg2.exec(str)); // ['a', index: 0, input: 'abcaefag', groups: undefined]
    },
    testRegEx16() {
      let str1 = "abcabdefag";
      console.log(str1.match(/[ae]/g)); //['a', 'a', 'e', 'a']

      let date = "2022/01-11";
      // let reg1 = /^\d{4}[-\/]\d{2}[-\/]\d{2}$/ // [-\/]这样会提示警告
      let reg1 = /^\d{4}[-\\/]\d{2}[-\\/]\d{2}$/; // [-\\/] 这样就不会
      console.log("采用元子表：", date.match(reg1)); // ['2022/01-11', index: 0, input: '2022/01-11', groups: undefined]

      // 采用原子组和原子表的结合，要求字符串原子表中的字符要求一致
      // "2022/01-11" /和-不一致，所以是null
      let reg2 = /^\d{4}([-\\/])\d{2}\1\d{2}$/;
      console.log("采用元子组和元子表结合：", date.match(reg2)); // null
    },

    testRegEx17() {
      let str1 = "2022a2023";
      // 区间表示
      console.log(str1.match(/[0-9]+/)); // ['2022', index: 0, input: '2022a2023', groups: undefined]
      console.log(str1.match(/[0-9]+/g)); // ['2022', '2023']

      let str2 = "abc12def";
      console.log(str2.match(/[a-z]+/g)); // ['abc', 'def']
    },
    testRegEx18() {
      let str1 = "../DEF/abc.md";
      // 采用排除，获取路劲的文件名
      console.log(
        "获取文件名：",
        str1.match(/[^\\.\\/]+/gi)[str1.match(/[^\\.\\/]+/gi).length - 2]
      );

      // 获取中文
      let str2 = "张三:010-7777777,李四:020-88888888";
      console.log("匹配中文1：", str2.match(/[^\d\-:]+/g)); // ['张三', ',李四']
    },

    testRegEx19() {
      let str = "(abcdefg)";
      //圆括号放在[]里面， [()]表示的是字符()
      console.log(str.match(/[(e)]/gi)); // ['(', 'e', ')']

      // 圆括号不在[]里面，()[]表示原子组
      console.log(str.match(/(e)/gi)); // ['e']

      // .+在[]里面 表示普通的.+字符
      console.log(str.match(/[.+]/)); // null

      // .+在[]外面 表示除了换行符的整个字符
      console.log(str.match(/.+/gi)); // ['(abcdefg)']
    },
    testRegEx20() {
      /**
       * \s 忽略换行符，也就是第9节提到的 “\s 视字符串为单行匹配”
       *  */
      let str1 = `
       acb
       惊呆了老铁
       `;
      console.log(str1.match(/.+/gs));
    },
    testRegEx21() {
      let vregularExpBox = document.getElementById("vregularExp");
      let reg = /<(h[1-6])>[\s\S]*<\/\1>/gi;
      setTimeout(() => {
        vregularExpBox.innerHTML = vregularExpBox.innerHTML.replace(reg, "");
      }, 5000);
    },
    testRegEx22() {
      let str = `
        <h1>vue</h1>
        <h2>js</h2>
        `;
      let reg = /<(h[1-6])>([\s\S]*)<\/\1>/i;
      console.dir(str.match(reg));

      // 原子组之后依次从 \1,\2 ... 计算
      let str2 = "123das123";
      let reg2 = /([1-9]{2,3})\w*\1/;
      console.log(str2.match(reg2));
    },

    testRegEx23() {
      let reg = /^[\w-]+@([\w-]+\.)+(com|org|qq|cn|net)$/i;
      console.log(this.mail.match(reg));
    },

    testRegEx24() {
      let str = `
        <h1>DCR</h1>
        <span>稻草人</span>
        <h2>abc</h2>
        `;
      let reg = /<(h[1-6])>([\s\S]+)<\/\1>/gi;
      console.log(str.match(reg));
      console.log(str.replace(reg, `$2`));

      // 采用函数的方式，原子组规则：从左到右，从外到里的次序递增计算
      let res1 = str.replace(reg, (p0, p1, p2) => {
        console.log("p0是匹配的字符串：", p0);
        console.log("p1是第一个原子组：", p1);
        console.log("p2是第二个原子组：", p2);
        return `<div>${p2}</div>`;
      });
      console.log("函数转换后：", res1);

      // 函数简写
      let res2 = str.replace(reg, (p0, p1, p2) => `<p>${p2}</p>`);
      console.log("函数简写：", res2);
    },

    testRegEx25() {
      let str = `
       https://www.baidu.com
       name = 稻草人
       https://www.daocaoren.com
       `;

      let reg = /https:\/\/(\w+\.\w+\.(com|org|cn))/gi;
      console.log("完整网址：", str.match(reg));

      let res1 = [];
      str.replace(reg, (p0, p1, p2) => {
        res1.push(p1);
      });
      console.log("网址：", res1);

      // ()外面的a? 表示字符a可有可无
      // (?:) 表示该原子组不做记录 就不可以使用 \1 ,$1 等对应的值

      let str2 = `
       http://www.baidu.com
       name = 稻草人
       https://www.daocaoren.com
       `;
      /**
       * https?表示：https也可以是http
       * (?:)表示：该原子组不做记录
       */
      let reg2 = /https?:\/\/((?:\w+\.)?\w+\.(?:com|org|cn))/gi;
      let urls = [];
      let res2 = "";
      while ((res2 = reg2.exec(str2))) {
        console.log(res2[1]);
        urls.push(res2[1]);
      }
      console.log("采用?的形式获取地址：", urls);
    },

    testRegEx27() {
      let tel = "0349-12345678";
      let reg = /^0\d{2,3}-\d{7,8}$/;
      console.log(tel.match(reg));
    },
    testRegEx28() {
      /**
       * [/^[a-z0-9]{1,3}$/i,/[A-Z]/,/\d/]
       *  1. /^[a-z0-9]{1,3}$/i 笼统的表示a-zA-Z0-9内容都可以输入
       *  2. /[A-Z]/ 表示一定要有A-Z
       *  3. /\d/ 表示一定要有0-9
       *  注意：他们的顺序不能颠倒（必须先笼统后精确）
       *  备注：例如错误的写法 [/^[a-z]{1,3}$/i,/[A-Z]/,/\d/]
       */
      let regs = [/^[a-z0-9]{1,3}$/i, /[A-Z]/, /\d/];
      let state = regs.every((e) => e.test(this.password));
      return state ? "正确" : "错误";
    },
    testRegEx29() {
      String.prototype.matchAll = function (reg) {
        let res = this.match(reg);
        if (res) {
          let strTemp = this.replace(res[0], "^".repeat(res[0].length));
          let match = strTemp.matchAll(reg) || [];
          return [res, ...match];
        }
      };
      let regs = /<(h[1-6])>([\s\S]+)<\/\1>/i;
      let str = `
        <h1>DCR</h1>
        name:小张
        <h2>搬砖人</h2>
        `;

      console.log(str.matchAll(regs));
      console.log("重复2两次*=", "*".repeat(2)); // 重复2两次*= **
    },

    testRegEx30() {
      function search(string, reg) {
        let result = [];
        let res = "";
        while ((res = reg.exec(string))) {
          result.push(res);
        }

        return result;
      }

      let regs = /<(h[1-6])>([\s\S]+)<\/\1>/gi;
      let str = `
        <h1>DCR</h1>
        name:小张
        <h2>搬砖人</h2>
        `;

      console.log(search(str, regs));
    },

    testRegEx31() {
      let str = `
        https://www.baidu.com
        http://www.qq.com
        https://dcr.cn
        https://abc.bb
        `;
      let reg = /https?:\/\/(\w+\.)?(\w+\.)+(com|cn)/gi;
      console.log(str.match(reg));
    },

    testRegEx32() {
      let str = `
      ./aa.md
      ../dcr/dd.md
      ../dcr/bb.md
      ../../ee.md
      ../../drc/ff.md
      `;
      let reg = /(\w+)\.\w+/gi;
      let res = "";
      let fileNames = [];
      while ((res = reg.exec(str))) {
        fileNames.push(res[1]);
      }
      console.log("文件名：", fileNames);
    },

    testRegEx33() {
      let str = `2022-01-10`;
      let reg = /[-\/]/gi;
      let res = str.split(reg);
      console.log(res);
    },

    testRegEx34() {
      let str1 = "(010)22222222 (021)33333333";
      let reg1 = /\((\d{3,4})\)(\d{7,8})/g;
      str1 = str1.replace(reg1, "$1-$2");
      console.log(str1); // 010-22222222 021-33333333

      /**
       * $` 表示的是匹配内容的前一个字符
       * $' 表示的是匹配内容的后一个字符
       * $& 表示的是原始内容
       */
      let str2 = "@稻草人#";
      console.log(str2.replace(/稻草人/, "$&")); // @稻草人#
      console.log(str2.replace(/稻草人/, "$'")); // @##
      console.log(str2.replace(/稻草人/, "$`")); // @@#
    },

    testRegEx35() {
      $("#myContent35")[0].innerHTML = $("#myContent35")[0].innerHTML.replace(
        /正则/,
        `<a href="https://www.runoob.com/regexp/regexp-tutorial.html" 
      target="_blank">$&</a>`
      );
    },

    testRegEx37() {
      const main = document.querySelector("#myContent36");
      console.log("main==", main);
      const reg = /(<a href=['"])(https?)(:\/\/)(www\.)?(dcr|hmgdcr|yahoo)/gi;
      main.innerHTML = main.innerHTML.replace(reg, (v, ...args) => {
        console.log(v);
        console.log("args==", args);
        args[1] = "https";
        args[4] = "hmgdcrstudyvue";
        return args.splice(0, 5).join("");
      });
    },
    testRegEx38() {
      let str = `
      <h1>HMGDCRVUE</h1>
      <span>稻草人</span>
      <h2>dcr</h2>
      `;
      let reg1 = /<(h[1-6])>(.*?)<\/\1>/gi;
      let reg2 = /<(h[1-6])>(?<con>.*?)<\/\1>/gi; // ?<con> 是给组(.*?)起的别名con
      console.log("reg1=", str.replace(reg1, "<h4>$2</h4>"));
      console.log("reg2=", str.replace(reg2, "<h4>$<con></h4>"));
    },

    testRegEx39() {
      let main = document.querySelector("#myContent36");
      const reg =
        /<a.*?href=(['"])(?<link>.*?)(style=['"].*?)?>(?<title>.*?)<\/a>/gi;
      let links = [];
      for (let iterator of main.innerHTML.matchAll(reg)) {
        links.push(iterator["groups"]);
      }
      console.log("links==", links);
    },

    testRegEx40() {
      let reg = /^[\w-]+@(\w+\.)+(com|cn|org|con)$/i;
      this.isEmail = reg.test(this.email);
      console.log("结果：", this.isEmail);
    },

    testRegEx41() {
      let reg = /(稻草人)/gi;
      let content = $("#content41")[0].innerHTML;
      while (reg.exec(content)) {
        this.num++;
      }
      $("#content41")[0].innerHTML = content.replace(reg, (v, p1) => {
        return `<span style="color:red;">${p1}</span>`;
      });
    },

    testRegEx42() {
      /**
       * ?=xx 表示后面紧接的是字符 xx
       * ?<=xx 表示前面紧接的是字符 xx
       */

      let content1 = $("#content42")[0].innerHTML;
      const reg1 = /((?<=AA)正则(?=CC))/gi;
      $("#content42")[0].innerHTML = content1.replace(reg1, (v, p1) => {
        return `<span style="color:blue;">${p1}</span>`;
      });
    },

    testRegEx43() {
      let tel = `
      12345670100,
      12345670110,
      12345670101,
      `;
      let reg = /(?<=\d{7})\d{4}/gi;
      tel = tel.replace(reg, () => {
        return "*".repeat(4);
      });
      console.log("tel=", tel);
    },

    testRegEx44() {
      /**
       * ?! 表示不是什么
       */
      //查找后面不是数字的字符串
      let str = "dcr123abc";
      let reg = /[a-z]+(?!\d)$/gi;
      // 注意：如果要找的是不是以XX结尾，记得要加上$，否则结果是['dc', 'abc']，我们期待的结果是['abc']
      console.log(str.match(reg));
    },

    testRegEx45() {
      // 表示任意位置都不能出现 “稻草人”字符
      let reg = /^(?!.*稻草人.*).{5,6}$/i;
      this.enSearch = reg.test(this.search);
    },

    testRegEx46() {
      /**
       * (?<!XX) 表示前面不是XX
       */
      let str = "abcd123DCBA";
      let reg = /(?<!\d)[a-z]+/i;
      console.log(str.match(reg));
      //结果： ['abcd', index: 0, input: 'abcd123DCBA', groups: undefined]
    },

    testRegEx47() {
      let tel = ["19879928459", "19734218976", "19623210987"];
      let reg = /(?<=\d{3})(\d{4})(?=\d{4})/i;
      const model = {
        "*": "*".repeat(4),
        "-": "-$&-",
        " ": " $& "
      };


      let prams = '*'

      let res1 = tel.map((item) => {
        return item = item.replace(reg,model[prams]);
      });
      console.log(res1);
    },
  },
  mounted() {
    this.testRegEx47();
  },
};
</script>